package com.tgjorgoski.utils;

import javax.swing.*;

/**
 * A utility class for caching more swing update operations
 * 
 * @author Tanasije Gjorgoski <tanas@ameritege.com>
 */
public class CalmRunner implements Runnable {
	
	Thread thread;
	long ifNotInterruptedFor;
	Runnable runProcedure;
	boolean notInEDT;
	
	public CalmRunner(Runnable runProcedure, long ifNotInterruptedFor, boolean notInEDT) {
		this.runProcedure=runProcedure;
		this.ifNotInterruptedFor=ifNotInterruptedFor;
		this.notInEDT=notInEDT;
	}
	public CalmRunner(Runnable runProcedure, long ifNotInterruptedFor) {
		this(runProcedure, ifNotInterruptedFor, false);
	}
	
	public void run() {
		if (thread==null || !thread.isAlive()) {
			thread = new TimerThread(ifNotInterruptedFor, runProcedure);
			thread.start();
		} else {
		    //interrupt either countdown to doing the work, or waiting for next one
			thread.interrupt();
		}
	}

	class TimerThread extends Thread {
		long time;
		Runnable runnable;
		public TimerThread(long time, Runnable runnable) {
			this.time=time;
			this.runnable=runnable;	
		}
		public void run() {
			Object c = new Object();
			boolean interrupted;
			while(true) {
			    //wait certain time or if interrupted start again
			    synchronized(c) {
					do {
						interrupted=false;
						try {
							c.wait(time);
						}
						catch (InterruptedException exc) {
							interrupted=true;
						}
					} while(interrupted==true);
				}
			    //now do the swing work
			    if (notInEDT) {
			    	runnable.run();
			    } else {
					SwingUtilities.invokeLater(runnable);
			    }
				//now wait for new call
				synchronized(c) {
				    boolean timeout=true;
				    try {
				        //if not interrupted for 40s, stop the thread
				        //so we don't hold the refference to the runnable
				        c.wait(40000);
				    } catch (InterruptedException exc) {
				        timeout=false;
				        //do nothing, just go back to waiting
				        //to the start
				    }
				    if (timeout) break;
				}
			}
		}
	}
	
}
